<template>
    <div class="wrapper">
        <div class="btn-box">
            <el-button
                type="primary"
                size="mini"
                @click="startFlow"
                v-if="!isStart"
                >开始流动</el-button
            >
            <el-button type="info" size="mini" @click="stopFlow" v-else
                >停止流动</el-button
            >
            <el-button
                type="primary"
                v-if="!isShowSolidLine"
                size="mini"
                @click="clearSolidLineCanvas"
                >隐藏实线</el-button
            >
            <el-button type="info" v-else size="mini" @click="drawSolidLine"
                >显示实线</el-button
            >
            <el-button type="success" size="mini" @click="clearBasicCanvas"
                >清除基本图形画布</el-button
            >
        </div>
        <div class="img-box">
            <canvas
                id="imgCanvasId"
                :width="canvasWidth"
                :height="canvasHeight"
            ></canvas>
        </div>
        <div class="basic-box">
            <canvas
                id="basicCanvasId"
                :width="canvasWidth"
                :height="canvasHeight"
            ></canvas>
        </div>
        <div class="static-line-box">
            <canvas
                id="solidLineCanvasId"
                :width="canvasWidth"
                :height="canvasHeight"
            ></canvas>
        </div>
        <div class="graph-box">
            <canvas
                id="dashedLineCanvasId"
                :width="canvasWidth"
                :height="canvasHeight"
            ></canvas>
        </div>
    </div>
</template>
<script>
import lineImg from "@/assets/line.png";
export default {
    data() {
        return {
            canvasWidth: 1200,
            canvasHeight: 600,
            dashedLineCtx: null,
            dashedLineCanvas: null,
            solidLineCanvas: null,
            solidLineCtx: null,
            imgCanvas: null,
            imgCtx: null,
            timer: null,
            isStart: false,
            options: [
                {
                    shape: "rect", // rect、ellipse
                    position: {
                        x: 615, // 矩形左上角x坐标
                        y: 60, // 矩形左上角y坐标
                        width: 110, // 矩形宽度
                        height: 200, // 矩形高度
                    },
                    color: "red",
                    lineWidth: 2,
                    lineDash: [20, 20], // 设置虚线长度
                    offset: 0, // 设置虚线偏移量
                    direction: true, // 方向，true为顺时针，false为逆时针
                    textOption: {
                        textSize: 20,
                        textColor: "#ffc700",
                        textContent: "4号变出线柜",
                        textPosition: {
                            x: 610,
                            y: 45,
                        },
                    },
                },
                {
                    shape: "ellipse", // rect、ellipse
                    position: {
                        x: 720, // 圆心x坐标
                        y: 318, // 圆心y坐标
                        width: 160, // 长轴半径
                        height: 80, // 短轴半径
                    },
                    color: "#199b33",
                    lineWidth: 2,
                    lineDash: [15, 15], // 设置虚线
                    offset: 0, // 设置虚线偏移量
                    direction: false, // 方向，true为顺时针，false为逆时针
                    textOption: {
                        textSize: 20,
                        textColor: "#bf197d",
                        textContent: "5号正常",
                        textPosition: {
                            x: 670,
                            y: 315,
                        },
                    },
                },
            ],
            basicCanvas: null,
            basicCtx: null,
            isShowSolidLine: true,
        };
    },
    mounted() {
        this.initCanvas();
    },
    destroyed() {
        if (this.timer) {
            clearInterval(this.timer);
        }
        this.timer = null;
    },
    methods: {
        initCanvas() {
            this.drawBackgroundImg();
            this.drawBasic();
            this.drawSolidLine();
            this.setDashedLineCanvas();
        },
        drawBackgroundImg() {
            this.imgCanvas = document.getElementById("imgCanvasId");
            if (!this.imgCanvas.getContext) return;
            this.imgCtx = this.imgCanvas.getContext("2d");
            const { width, height } = this.imgCanvas;
            const img = new Image();
            img.src = lineImg;
            img.onload = () => {
                this.imgCtx.drawImage(img, 0, 0, width, height);
            };
        },
        setDashedLineCanvas() {
            this.dashedLineCanvas =
                document.getElementById("dashedLineCanvasId");
            if (!this.dashedLineCanvas.getContext) return;
            this.dashedLineCtx = this.dashedLineCanvas.getContext("2d");
        },
        // 封装流动虚线
        drawDashedLine(option) {
            const {
                shape,
                position,
                color,
                lineWidth,
                lineDash,
                offset,
                direction,
            } = option;
            // 先清空当前画布
            const { x, y, width, height } = position;
            /*
             * this.dashedLineCtx.clearRect(x, y, width, height);
             * 按说应该直接清除当前点位区域，但是发现会导致画布上留有残影，所以这里将范围稍扩大点
             * 经测试发现直接清除整个画布或将50/100改为别的值，效果均不理想
             * 暂时先这样处理，后续有更好的解决方案再改
             */
            this.dashedLineCtx.clearRect(
                x - 50,
                y - 50,
                width + 100,
                height + 100
            );
            // 开始绘制
            this.dashedLineCtx.beginPath();
            this.dashedLineCtx.lineWidth = lineWidth;
            this.dashedLineCtx.setLineDash(lineDash); // 设置虚线
            const totalOffset = lineDash.reduce((acc, cur) => acc + cur, 0);
            const newOffset =
                offset >= totalOffset ? 0 : direction ? offset + 5 : offset - 5; // 当偏移量大于等于虚线总长度时，重新从0开始 并且通过加/减5控制旋转方向
            option.offset = newOffset;
            this.dashedLineCtx.lineDashOffset = newOffset; // 设置虚线偏移量
            this.dashedLineCtx.strokeStyle = color;
            if (shape === "rect") {
                this.dashedLineCtx.rect(
                    position.x,
                    position.y,
                    position.width,
                    position.height
                );
            } else if (shape === "ellipse") {
                const { x, y, width, height } = position;
                const rotation = Math.PI; // 旋转角度
                const startAngle = 0; // 起始角度
                const endAngle = 2 * Math.PI; // 终止角度
                this.dashedLineCtx.ellipse(
                    x + width / 2,
                    y + height / 2,
                    width / 2,
                    height / 2,
                    rotation,
                    startAngle,
                    endAngle
                );
            }
            this.dashedLineCtx.stroke();
        },
        startFlow() {
            const options = this.options;
            const _this = this;
            this.timer = setInterval(() => {
                options.forEach((item) => {
                    _this.drawDashedLine(item);
                });
            }, 80);
            this.isStart = true;
        },
        stopFlow() {
            clearInterval(this.timer);
            this.isStart = false;
        },
        drawSolidLine() {
            this.isShowSolidLine = !this.isShowSolidLine;
            this.solidLineCanvas = document.getElementById("solidLineCanvasId");
            if (!this.solidLineCanvas.getContext) return;
            this.solidLineCtx = this.solidLineCanvas.getContext("2d");
            const options = this.options;
            options.forEach((item) => {
                this.solidLineCtx.beginPath();
                if (item.shape === "rect") {
                    const { x, y, width, height } = item.position;
                    this.solidLineCtx.strokeStyle = "#ffc700";
                    this.solidLineCtx.lineWidth = 4;
                    this.solidLineCtx.rect(x, y, width, height);
                    this.solidLineCtx.stroke();
                } else if (item.shape === "ellipse") {
                    const { x, y, width, height } = item.position;
                    const rotation = Math.PI; // 旋转角度
                    const startAngle = 0; // 起始角度
                    const endAngle = 2 * Math.PI; // 终止角度
                    this.solidLineCtx.strokeStyle = "#bf197d";
                    this.solidLineCtx.lineWidth = 6;
                    this.solidLineCtx.ellipse(
                        x + width / 2,
                        y + height / 2,
                        width / 2,
                        height / 2,
                        rotation,
                        startAngle,
                        endAngle
                    );
                    this.solidLineCtx.stroke();
                }

                // 文字位置
                const { textSize, textColor, textContent, textPosition } =
                    item.textOption;
                this.solidLineCtx.fillStyle = textColor;
                this.solidLineCtx.font = `${textSize}px microsoft yahei,simhei`;
                this.solidLineCtx.fillText(
                    textContent,
                    textPosition.x,
                    textPosition.y
                );
                this.solidLineCtx.stroke();
            });
        },
        clearSolidLineCanvas() {
            this.isShowSolidLine = !this.isShowSolidLine;
            this.solidLineCtx.clearRect(
                0,
                0,
                this.solidLineCanvas.width,
                this.solidLineCanvas.height
            );
        },

        /*************** 基本图形绘制 *****************/
        drawBasic() {
            this.basicCanvas = document.getElementById("basicCanvasId");
            if (!this.basicCanvas.getContext) return;
            this.basicCtx = this.basicCanvas.getContext("2d");
            // 矩形
            this.basicCtx.strokeStyle = "#10f";
            this.basicCtx.lineWidth = 5;
            this.basicCtx.rect(50, 50, 100, 100);
            this.basicCtx.stroke();

            // 三角形
            this.basicCtx.beginPath();
            this.basicCtx.moveTo(50, 250);
            this.basicCtx.lineTo(100, 200);
            this.basicCtx.lineTo(150, 250);
            this.basicCtx.closePath();
            this.basicCtx.stroke();

            // 菱形
            this.basicCtx.beginPath();
            this.basicCtx.moveTo(100, 300);
            this.basicCtx.lineTo(50, 350);
            this.basicCtx.lineTo(100, 400);
            this.basicCtx.lineTo(150, 350);
            this.basicCtx.closePath();
            this.basicCtx.stroke();
        },
        clearBasicCanvas() {
            this.basicCtx.clearRect(
                0,
                0,
                this.basicCanvas.width,
                this.basicCanvas.height
            );
        },
    },
};
</script>

<style lang="less" scoped>
.wrapper {
    position: relative;
    height: 660px;
}
canvas {
    background: transparent;
}
.img-box,
.basic-box,
.static-line-box,
.graph-box {
    position: absolute;
    top: 50px;
    left: 0;
    width: 100%;
    height: 100%;
}
.img-box {
    z-index: 1;
}
.basic-box {
    z-index: 2;
}
.static-line-box {
    z-index: 3;
}
.graph-box {
    z-index: 4;
}
</style>
